home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Samples / C++ / DirectSound / Play3DSound / play3dsound.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-09-27  |  31.0 KB  |  845 lines

  1. //----------------------------------------------------------------------------
  2. // File: Play3DSound.cpp
  3. //
  4. // Desc: Main application file for the Play3DSound sample. This sample shows how
  5. //       to load a wave file and play it using a 3D DirectSound buffer.
  6. //
  7. // Copyright (c) Microsoft Corp. All rights reserved.
  8. //-----------------------------------------------------------------------------
  9. #include "dxstdafx.h"
  10. #include <commctrl.h>
  11. #include <commdlg.h>
  12. #include "resource.h"
  13.  
  14.  
  15.  
  16. //-----------------------------------------------------------------------------
  17. // Function-prototypes
  18. //-----------------------------------------------------------------------------
  19. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  20. VOID    OnInitDialog( HWND hDlg );
  21. HRESULT InitDirectSound( HWND hDlg );
  22. HRESULT FreeDirectSound();
  23. VOID    SetSlidersPos( HWND hDlg, FLOAT fDopplerValue, FLOAT fRolloffValue, FLOAT fMinDistValue, FLOAT fMaxDistValue );
  24. VOID    OnOpenSoundFile( HWND hDlg );
  25. VOID    LoadWaveFileIntoBuffer( HWND hDlg, TCHAR* strFileName );
  26. INT_PTR CALLBACK AlgorithmDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
  27. HRESULT OnPlaySound( HWND hDlg );
  28. VOID    OnSliderChanged( HWND hDlg );
  29. VOID    Set3DParameters( FLOAT fDopplerFactor, FLOAT fRolloffFactor, FLOAT fMinDistance,   FLOAT fMaxDistance );
  30. VOID    EnablePlayUI( HWND hDlg, BOOL bEnable );
  31. VOID    OnMovementTimer( HWND hDlg );
  32. VOID    UpdateGrid( HWND hDlg, FLOAT x, FLOAT y );
  33. VOID    SetObjectProperties( D3DVECTOR* pvPosition, D3DVECTOR* pvVelocity );
  34. FLOAT   ConvertLinearSliderPosToLogScale( LONG lSliderPos );
  35. LONG    ConvertLogScaleToLinearSliderPosTo( FLOAT fValue );
  36.  
  37.  
  38.  
  39.  
  40. //-----------------------------------------------------------------------------
  41. // Defines, constants, and global variables
  42. //-----------------------------------------------------------------------------
  43. #define SAFE_DELETE(p)  { if(p) { delete (p);     (p)=NULL; } }
  44. #define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
  45.  
  46. #define ORBIT_MAX_RADIUS        5.0f
  47. #define IDT_MOVEMENT_TIMER      1
  48.  
  49. CSoundManager*          g_pSoundManager       = NULL;
  50. CSound*                 g_pSound              = NULL;
  51. LPDIRECTSOUND3DBUFFER   g_pDS3DBuffer         = NULL;   // 3D sound buffer
  52. LPDIRECTSOUND3DLISTENER g_pDSListener         = NULL;   // 3D listener object
  53. DS3DBUFFER              g_dsBufferParams;               // 3D buffer properties
  54. DS3DLISTENER            g_dsListenerParams;             // Listener properties
  55. BOOL                    g_bDeferSettings      = FALSE;
  56. BOOL                    g_bAllowMovementTimer = TRUE;
  57. HBITMAP                 g_hGrid               = NULL;   // Grid Bitmap object
  58. INT                     g_nGridW, g_nGridH;             // and dimensions
  59.  
  60.  
  61.  
  62.  
  63. //-----------------------------------------------------------------------------
  64. // Name: WinMain()
  65. // Desc: Entry point for the application.  Since we use a simple dialog for 
  66. //       user interaction we don't need to pump messages.
  67. //-----------------------------------------------------------------------------
  68. INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, 
  69.                       INT nCmdShow )
  70. {
  71.     // Init the common control dll 
  72.     InitCommonControls();
  73.  
  74.     // Display the main dialog box.
  75.     DialogBox( hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, MainDlgProc );
  76.  
  77.     return TRUE;
  78. }
  79.  
  80.  
  81.  
  82.  
  83. //-----------------------------------------------------------------------------
  84. // Name: MainDlgProc()
  85. // Desc: Handles dialog messages
  86. //-----------------------------------------------------------------------------
  87. INT_PTR CALLBACK MainDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  88. {
  89.     HRESULT hr;
  90.  
  91.     switch( msg ) 
  92.     {
  93.         case WM_INITDIALOG:
  94.             OnInitDialog( hDlg );
  95.             break;
  96.  
  97.         case WM_COMMAND:
  98.             switch( LOWORD(wParam) )
  99.             {
  100.                 case IDC_SOUNDFILE:
  101.                     OnOpenSoundFile( hDlg );
  102.                     break;
  103.  
  104.                 case IDCANCEL:
  105.                     EndDialog( hDlg, IDCANCEL );
  106.                     break;
  107.  
  108.                 case IDC_PLAY:
  109.                     if( FAILED( hr = OnPlaySound( hDlg ) ) )
  110.                     {
  111.                         DXTRACE_ERR_MSGBOX( TEXT("OnPlaySound"), hr );
  112.                         MessageBox( hDlg, L"Error playing DirectSound buffer."
  113.                                     L"Sample will now exit.", L"DirectSound Sample", 
  114.                                     MB_OK | MB_ICONERROR );
  115.                         EndDialog( hDlg, IDABORT );
  116.                     }
  117.                     break;
  118.  
  119.                 case IDC_STOP:
  120.                     if( g_pSound )
  121.                     {
  122.                         g_pSound->Stop();
  123.                         g_pSound->Reset();
  124.                     }
  125.  
  126.                     // Update the UI controls to show the sound as stopped
  127.                     EnablePlayUI( hDlg, TRUE );
  128.                     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Sound stopped.") );
  129.                     break;
  130.  
  131.                 case IDC_DEFER:
  132.                     g_bDeferSettings = !g_bDeferSettings;
  133.                     OnSliderChanged( hDlg );                    
  134.                     break;
  135.  
  136.                 case IDC_APPLY:
  137.                     // Call the IDirectSound3DListener::CommitDeferredSettings 
  138.                     // method to execute all of the deferred commands at once.
  139.                     // This is many times more efficent than recomputing everything
  140.                     // for every call.
  141.                     if( g_pDSListener )
  142.                         g_pDSListener->CommitDeferredSettings();
  143.                     break;
  144.  
  145.                 default:
  146.                     return FALSE; // Didn't handle message
  147.             }
  148.             break;
  149.  
  150.         case WM_TIMER:
  151.             if( wParam == IDT_MOVEMENT_TIMER )
  152.                 OnMovementTimer( hDlg );
  153.             break;
  154.  
  155.         case WM_NOTIFY:
  156.             OnSliderChanged( hDlg );
  157.             break;
  158.  
  159.         case WM_DESTROY:
  160.             // Cleanup everything
  161.             KillTimer( hDlg, 1 );    
  162.             SAFE_RELEASE( g_pDSListener );
  163.             SAFE_RELEASE( g_pDS3DBuffer );
  164.  
  165.             SAFE_DELETE( g_pSound );
  166.             SAFE_DELETE( g_pSoundManager );
  167.             break; 
  168.             
  169.         default:
  170.             return FALSE; // Didn't handle message
  171.     }
  172.  
  173.     return TRUE; // Handled message
  174. }
  175.  
  176.  
  177.  
  178.  
  179. //-----------------------------------------------------------------------------
  180. // Name: OnInitDialog()
  181. // Desc: Initializes the dialogs (sets up UI controls, etc.)
  182. //-----------------------------------------------------------------------------
  183. VOID OnInitDialog( HWND hDlg )
  184. {
  185.     HRESULT hr;
  186.  
  187.     // Load the icon
  188. #ifdef _WIN64
  189.     HINSTANCE hInst = (HINSTANCE) GetWindowLongPtr( hDlg, GWLP_HINSTANCE );
  190. #else
  191.     HINSTANCE hInst = (HINSTANCE) GetWindowLong( hDlg, GWL_HINSTANCE );
  192. #endif
  193.     HICON hIcon = LoadIcon( hInst, MAKEINTRESOURCE( IDR_MAINFRAME ) );
  194.     g_hGrid = LoadBitmap( hInst, MAKEINTRESOURCE( IDB_GRID_BITMAP ) );
  195.  
  196.     // Create a static IDirectSound in the CSound class.  
  197.     // Set coop level to DSSCL_PRIORITY, and set primary buffer 
  198.     // format to stereo, 22kHz and 16-bit output.
  199.     g_pSoundManager = new CSoundManager();
  200.     if( NULL == g_pSoundManager )
  201.     {
  202.         DXTRACE_ERR_MSGBOX( TEXT("Initialize"), E_OUTOFMEMORY );
  203.         EndDialog( hDlg, IDABORT );
  204.         return;
  205.     }
  206.  
  207.     hr = g_pSoundManager->Initialize( hDlg, DSSCL_PRIORITY );
  208.        
  209.     hr |= g_pSoundManager->SetPrimaryBufferFormat( 2, 22050, 16 );
  210.     
  211.     // Get the 3D listener, so we can control its params
  212.     hr |= g_pSoundManager->Get3DListenerInterface( &g_pDSListener );
  213.  
  214.     if( FAILED(hr) )
  215.     {
  216.         DXTRACE_ERR_MSGBOX( TEXT("Get3DListenerInterface"), hr );
  217.         MessageBox( hDlg, L"Error initializing DirectSound.  Sample will now exit.", 
  218.                           L"DirectSound Sample", MB_OK | MB_ICONERROR );
  219.         EndDialog( hDlg, IDABORT );
  220.         return;
  221.     }
  222.  
  223.     // Get listener parameters
  224.     g_dsListenerParams.dwSize = sizeof(DS3DLISTENER);
  225.     g_pDSListener->GetAllParameters( &g_dsListenerParams );
  226.  
  227.     // Set the icon for this dialog.
  228.     PostMessage( hDlg, WM_SETICON, ICON_BIG,   (LPARAM) hIcon );  // Set big icon
  229.     PostMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon );  // Set small icon
  230.  
  231.     // Create a timer to periodically move the 3D object around
  232.     SetTimer( hDlg, IDT_MOVEMENT_TIMER, 0, NULL );
  233.  
  234.     // Set the UI controls
  235.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  236.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("No file loaded.") );
  237.  
  238.     // Get handles to dialog items
  239.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  240.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  241.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  242.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  243.     HWND hVertSlider     = GetDlgItem( hDlg, IDC_VERTICAL_SLIDER );
  244.     HWND hHorzSlider     = GetDlgItem( hDlg, IDC_HORIZONTAL_SLIDER );
  245.  
  246.     // Determine grid bitmap dimensions (used for clipping)
  247.     BITMAP bmp;
  248.     GetObject( g_hGrid, sizeof(BITMAP), &bmp );
  249.     g_nGridW = bmp.bmWidth;
  250.     g_nGridH = bmp.bmHeight;
  251.  
  252.     // Set the range and position of the sliders
  253.     PostMessage( hDopplerSlider, TBM_SETRANGEMAX, TRUE, ConvertLogScaleToLinearSliderPosTo( DS3D_MAXDOPPLERFACTOR ) );
  254.     PostMessage( hDopplerSlider, TBM_SETRANGEMIN, TRUE, ConvertLogScaleToLinearSliderPosTo( DS3D_MINDOPPLERFACTOR ) );
  255.  
  256.     PostMessage( hRolloffSlider, TBM_SETRANGEMAX, TRUE, ConvertLogScaleToLinearSliderPosTo( DS3D_MAXROLLOFFFACTOR ) );
  257.     PostMessage( hRolloffSlider, TBM_SETRANGEMIN, TRUE, ConvertLogScaleToLinearSliderPosTo( DS3D_MINROLLOFFFACTOR ) );
  258.  
  259.     PostMessage( hMinDistSlider, TBM_SETRANGEMAX, TRUE, 40L );
  260.     PostMessage( hMinDistSlider, TBM_SETRANGEMIN, TRUE, 1L );
  261.  
  262.     PostMessage( hMaxDistSlider, TBM_SETRANGEMAX, TRUE, 40L );
  263.     PostMessage( hMaxDistSlider, TBM_SETRANGEMIN, TRUE, 1L );
  264.  
  265.     PostMessage( hVertSlider,    TBM_SETRANGEMAX, TRUE, 100L );
  266.     PostMessage( hVertSlider,    TBM_SETRANGEMIN, TRUE, -100L );
  267.     PostMessage( hVertSlider,    TBM_SETPOS,      TRUE, 100L );
  268.  
  269.     PostMessage( hHorzSlider,    TBM_SETRANGEMAX, TRUE, 100L );
  270.     PostMessage( hHorzSlider,    TBM_SETRANGEMIN, TRUE, -100L );
  271.     PostMessage( hHorzSlider,    TBM_SETPOS,      TRUE, 100L );
  272.  
  273.     // Set the position of the sliders
  274.     SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f );
  275. }
  276.  
  277.  
  278.  
  279.  
  280. //-----------------------------------------------------------------------------
  281. // Name: SetSlidersPos()
  282. // Desc: Sets the slider positions
  283. //-----------------------------------------------------------------------------
  284. VOID SetSlidersPos( HWND hDlg, FLOAT fDopplerValue, FLOAT fRolloffValue,
  285.                     FLOAT fMinDistValue, FLOAT fMaxDistValue )
  286. {
  287.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  288.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  289.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  290.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  291.  
  292.     LONG lDopplerSlider = ConvertLogScaleToLinearSliderPosTo( fDopplerValue );
  293.     LONG lRolloffSlider = ConvertLogScaleToLinearSliderPosTo( fRolloffValue );
  294.     LONG lMinDistSlider = ConvertLogScaleToLinearSliderPosTo( fMinDistValue );
  295.     LONG lMaxDistSlider = ConvertLogScaleToLinearSliderPosTo( fMaxDistValue );
  296.  
  297.     PostMessage( hDopplerSlider, TBM_SETPOS, TRUE, lDopplerSlider );
  298.     PostMessage( hRolloffSlider, TBM_SETPOS, TRUE, lRolloffSlider );
  299.     PostMessage( hMinDistSlider, TBM_SETPOS, TRUE, lMinDistSlider );
  300.     PostMessage( hMaxDistSlider, TBM_SETPOS, TRUE, lMaxDistSlider );
  301. }
  302.  
  303.  
  304.  
  305.  
  306. //-----------------------------------------------------------------------------
  307. // Name: OnOpenSoundFile()
  308. // Desc: Called when the user requests to open a sound file
  309. //-----------------------------------------------------------------------------
  310. VOID OnOpenSoundFile( HWND hDlg ) 
  311. {
  312.     GUID    guid3DAlgorithm = GUID_NULL;
  313.     int     nResult;
  314.     HRESULT hr; 
  315.  
  316.     static TCHAR strFileName[MAX_PATH] = TEXT("");
  317.     static TCHAR strPath[MAX_PATH] = TEXT("");
  318.  
  319.     // Setup the OPENFILENAME structure
  320.     OPENFILENAME ofn = { sizeof(OPENFILENAME), hDlg, NULL,
  321.                          TEXT("Wave Files\0*.wav\0All Files\0*.*\0\0"), NULL,
  322.                          0, 1, strFileName, MAX_PATH, NULL, 0, strPath,
  323.                          TEXT("Open Sound File"),
  324.                          OFN_FILEMUSTEXIST|OFN_HIDEREADONLY, 0, 0,
  325.                          TEXT(".wav"), 0, NULL, NULL };
  326.  
  327.     // Get the default media path (something like C:\WINDOWS\MEDIA)
  328.     if( '\0' == strPath[0] )
  329.     {
  330.         if( GetWindowsDirectory( strPath, MAX_PATH ) != 0 )
  331.         {
  332.             if( wcscmp( &strPath[wcslen(strPath)], TEXT("\\") ) )
  333.                 wcscat( strPath, TEXT("\\") );
  334.             wcscat( strPath, TEXT("MEDIA") );
  335.         }
  336.     }
  337.  
  338.     if( g_pSound )
  339.     {
  340.         g_pSound->Stop();
  341.         g_pSound->Reset();
  342.     }
  343.  
  344.     // Update the UI controls to show the sound as loading a file
  345.     EnableWindow( GetDlgItem( hDlg, IDC_PLAY ), FALSE);
  346.     EnableWindow( GetDlgItem( hDlg, IDC_STOP ), FALSE);
  347.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Loading file...") );
  348.  
  349.     // Stop the timer while dialogs are displayed
  350.     g_bAllowMovementTimer = FALSE;
  351.  
  352.     // Display the OpenFileName dialog. Then, try to load the specified file
  353.     if( TRUE != GetOpenFileName( &ofn ) )
  354.     {
  355.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") );
  356.         g_bAllowMovementTimer = TRUE;
  357.         return;
  358.     }
  359.  
  360.     SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  361.  
  362.     // Free any previous sound, and make a new one
  363.     SAFE_DELETE( g_pSound );
  364.  
  365.     // Verify the file is small
  366.     HANDLE hFile = CreateFile( strFileName, 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL );
  367.     if( hFile != NULL )
  368.     {
  369.         // If you try to open a 100MB wav file, you could run out of system memory with this
  370.         // sample cause it puts all of it into a large buffer.  If you need to do this, then 
  371.         // see the "StreamData" sample to stream the data from the file into a sound buffer.
  372.         DWORD dwFileSizeHigh = 0;
  373.         DWORD dwFileSize = GetFileSize( hFile, &dwFileSizeHigh );
  374.         CloseHandle( hFile );
  375.  
  376.         if( dwFileSizeHigh != 0 || dwFileSize > 1000000 )
  377.         {
  378.             SetDlgItemText( hDlg, IDC_STATUS, TEXT("File too large.  You should stream large files.") );
  379.             return;
  380.         }
  381.     }
  382.  
  383.     CWaveFile waveFile;
  384.     waveFile.Open( strFileName, NULL, WAVEFILE_READ );
  385.     WAVEFORMATEX* pwfx = waveFile.GetFormat();
  386.     if( pwfx == NULL )
  387.     {
  388.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Invalid wave file format.") );
  389.         return;
  390.     }
  391.  
  392.     if( pwfx->nChannels > 1 )
  393.     {
  394.         // Too many channels in wave.  Sound must be mono when using DSBCAPS_CTRL3D
  395.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be mono for 3D control.") );
  396.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  397.         return;
  398.     }
  399.  
  400.     if( pwfx->wFormatTag != WAVE_FORMAT_PCM )
  401.     {
  402.         // Sound must be PCM when using DSBCAPS_CTRL3D
  403.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Wave file must be PCM for 3D control.") );
  404.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  405.         return;
  406.     }
  407.  
  408.     // Get the software DirectSound3D emulation algorithm to use
  409.     // Ask the user for this sample, so display the algorithm dialog box.
  410.     nResult = (int)DialogBox( NULL, MAKEINTRESOURCE(IDD_3D_ALGORITHM), 
  411.                               NULL, AlgorithmDlgProc );
  412.     switch( nResult )
  413.     {
  414.     case -1: // User canceled dialog box
  415.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Load aborted.") );
  416.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  417.         return;
  418.  
  419.     case 0: // User selected DS3DALG_NO_VIRTUALIZATION  
  420.         guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
  421.         break;
  422.  
  423.     case 1: // User selected DS3DALG_HRTF_FULL  
  424.         guid3DAlgorithm = DS3DALG_HRTF_FULL;
  425.         break;
  426.  
  427.     case 2: // User selected DS3DALG_HRTF_LIGHT
  428.         guid3DAlgorithm = DS3DALG_HRTF_LIGHT;
  429.         break;
  430.     }
  431.  
  432.     // Load the wave file into a DirectSound buffer
  433.     hr = g_pSoundManager->Create( &g_pSound, strFileName, DSBCAPS_CTRL3D, guid3DAlgorithm );  
  434.     if( FAILED( hr ) || hr == DS_NO_VIRTUALIZATION )
  435.     {
  436.         DXTRACE_ERR( TEXT("Create"), hr );
  437.         if( DS_NO_VIRTUALIZATION == hr )
  438.         {
  439.             MessageBox( hDlg, L"The 3D virtualization algorithm requested is not supported under this "
  440.                         L"operating system.  It is available only on Windows 2000, Windows ME, and Windows 98 with WDM "
  441.                         L"drivers and beyond.  Creating buffer with no virtualization.", 
  442.                         L"DirectSound Sample", MB_OK );
  443.         }
  444.  
  445.         // Unknown error, but not a critical failure, so just update the status
  446.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("Could not create sound buffer.") );
  447.         return; 
  448.     }
  449.  
  450.     // Get the 3D buffer from the secondary buffer
  451.     if( FAILED( hr = g_pSound->Get3DBufferInterface( 0, &g_pDS3DBuffer ) ) )
  452.     {
  453.         DXTRACE_ERR_MSGBOX( TEXT("Get3DBufferInterface"), hr );
  454.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("Could not get 3D buffer.") );
  455.         SetDlgItemText( hDlg, IDC_FILENAME, TEXT("") );
  456.         return;
  457.     }
  458.  
  459.     // Get the 3D buffer parameters
  460.     g_dsBufferParams.dwSize = sizeof(DS3DBUFFER);
  461.     g_pDS3DBuffer->GetAllParameters( &g_dsBufferParams );
  462.  
  463.     // Set new 3D buffer parameters
  464.     g_dsBufferParams.dwMode = DS3DMODE_HEADRELATIVE;
  465.     g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE );
  466.  
  467.     DSBCAPS dsbcaps;
  468.     ZeroMemory( &dsbcaps, sizeof(DSBCAPS) );
  469.     dsbcaps.dwSize = sizeof(DSBCAPS);
  470.  
  471.     LPDIRECTSOUNDBUFFER pDSB = g_pSound->GetBuffer( 0 );
  472.     pDSB->GetCaps( &dsbcaps );
  473.     if( ( dsbcaps.dwFlags & DSBCAPS_LOCHARDWARE ) != 0 )
  474.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using hardware mixing.") );
  475.     else
  476.         SetDlgItemText( hDlg, IDC_STATUS, TEXT("File loaded using software mixing.") );
  477.  
  478.     // Update the UI controls to show the sound as the file is loaded
  479.     SetDlgItemText( hDlg, IDC_FILENAME, strFileName );
  480.     EnablePlayUI( hDlg, TRUE );
  481.  
  482.     g_bAllowMovementTimer = TRUE;
  483.  
  484.     // Remember the path for next time
  485.     wcscpy( strPath, strFileName );
  486.     WCHAR* strLastSlash = wcsrchr( strPath, '\\' );
  487.     if( strLastSlash )
  488.         strLastSlash[0] = '\0';
  489.  
  490.     // Set the slider positions
  491.     SetSlidersPos( hDlg, 0.0f, 0.0f, ORBIT_MAX_RADIUS, ORBIT_MAX_RADIUS*2.0f );
  492.     OnSliderChanged( hDlg );
  493. }
  494.  
  495.  
  496.  
  497.  
  498. //-----------------------------------------------------------------------------
  499. // Name: AlgorithmDlgProc()
  500. // Desc: Handles dialog messages
  501. //-----------------------------------------------------------------------------
  502. INT_PTR CALLBACK AlgorithmDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam )
  503. {
  504.     // Default is DS3DALG_NO_VIRTUALIZATION for fastest performance
  505.     static int nDefaultRadio = IDC_NO_VIRT_RADIO;
  506.  
  507.     switch( msg ) 
  508.     {
  509.         case WM_INITDIALOG:
  510.             // Default is DS3DALG_NO_VIRTUALIZATION for fastest performance
  511.             CheckRadioButton( hDlg, IDC_NO_VIRT_RADIO, IDC_LIGHT_VIRT_RADIO, nDefaultRadio );
  512.             return TRUE; // Message handled 
  513.  
  514.         case WM_COMMAND:
  515.             switch( LOWORD(wParam) )
  516.             {
  517.                 case IDCANCEL:
  518.                     EndDialog( hDlg, -1 );
  519.                     return TRUE; // Message handled 
  520.  
  521.                 case IDOK:
  522.                     if( IsDlgButtonChecked( hDlg, IDC_NO_VIRT_RADIO )    == BST_CHECKED )
  523.                     {
  524.                         nDefaultRadio = IDC_NO_VIRT_RADIO;
  525.                         EndDialog( hDlg, 0 );
  526.                     }
  527.  
  528.                     if( IsDlgButtonChecked( hDlg, IDC_HIGH_VIRT_RADIO )  == BST_CHECKED )
  529.                     {               
  530.                         nDefaultRadio = IDC_HIGH_VIRT_RADIO;
  531.                         EndDialog( hDlg, 1 );
  532.                     }
  533.  
  534.                     if( IsDlgButtonChecked( hDlg, IDC_LIGHT_VIRT_RADIO ) == BST_CHECKED )
  535.                     {               
  536.                         nDefaultRadio = IDC_LIGHT_VIRT_RADIO;
  537.                         EndDialog( hDlg, 2 );
  538.                     }
  539.                         
  540.                     return TRUE; // Message handled 
  541.             }
  542.             break;
  543.     }
  544.  
  545.     return FALSE; // Message not handled 
  546. }
  547.  
  548.  
  549.  
  550.  
  551. //-----------------------------------------------------------------------------
  552. // Name: OnPlaySound()
  553. // Desc: User hit the "Play" button
  554. //-----------------------------------------------------------------------------
  555. HRESULT OnPlaySound( HWND hDlg ) 
  556. {
  557.     HRESULT hr;
  558.  
  559.     if( NULL == g_pSound )
  560.         return E_FAIL;
  561.  
  562.     // Play buffer always in looped mode just for this sample
  563.     if( FAILED( hr = g_pSound->Play( 0, DSBPLAY_LOOPING ) ) )
  564.         return DXTRACE_ERR( TEXT("Play"), hr );
  565.  
  566.     // Update the UI controls to show the sound as playing
  567.     EnablePlayUI( hDlg, FALSE );
  568.     SetDlgItemText( hDlg, IDC_STATUS, TEXT("Sound playing.") );
  569.  
  570.     return S_OK;
  571. }
  572.  
  573.  
  574.  
  575.  
  576. //-----------------------------------------------------------------------------
  577. // Name: OnSliderChanged()  
  578. // Desc: Called when the dialog's slider bars are changed by the user, or need
  579. //       updating
  580. //-----------------------------------------------------------------------------
  581. VOID OnSliderChanged( HWND hDlg )
  582. {
  583.     TCHAR strBuffer[10];
  584.     FLOAT fDopplerFactor;
  585.     FLOAT fRolloffFactor;
  586.     FLOAT fMinDistance; 
  587.     FLOAT fMaxDistance;
  588.  
  589.     // Get handles to dialog items
  590.     HWND hDopplerSlider  = GetDlgItem( hDlg, IDC_DOPPLER_SLIDER );
  591.     HWND hRolloffSlider  = GetDlgItem( hDlg, IDC_ROLLOFF_SLIDER );
  592.     HWND hMinDistSlider  = GetDlgItem( hDlg, IDC_MINDISTANCE_SLIDER );
  593.     HWND hMaxDistSlider  = GetDlgItem( hDlg, IDC_MAXDISTANCE_SLIDER );
  594.  
  595.     // Get the position of the sliders
  596.     fDopplerFactor = ConvertLinearSliderPosToLogScale( (long)SendMessage( hDopplerSlider, TBM_GETPOS, 0, 0 ) );
  597.     fRolloffFactor = ConvertLinearSliderPosToLogScale( (long)SendMessage( hRolloffSlider, TBM_GETPOS, 0, 0 ) );
  598.     fMinDistance   = ConvertLinearSliderPosToLogScale( (long)SendMessage( hMinDistSlider, TBM_GETPOS, 0, 0 ) );
  599.     fMaxDistance   = ConvertLinearSliderPosToLogScale( (long)SendMessage( hMaxDistSlider, TBM_GETPOS, 0, 0 ) );
  600.  
  601.     // Set the static text boxes
  602.     swprintf( strBuffer, TEXT("%.2f"), fDopplerFactor );
  603.     SetWindowText( GetDlgItem( hDlg, IDC_DOPPLERFACTOR ), strBuffer );
  604.  
  605.     swprintf( strBuffer, TEXT("%.2f"), fRolloffFactor );
  606.     SetWindowText( GetDlgItem( hDlg, IDC_ROLLOFFFACTOR ), strBuffer );
  607.  
  608.     swprintf( strBuffer, TEXT("%.2f"), fMinDistance );
  609.     SetWindowText( GetDlgItem( hDlg, IDC_MINDISTANCE ), strBuffer );
  610.  
  611.     swprintf( strBuffer, TEXT("%.2f"), fMaxDistance );
  612.     SetWindowText( GetDlgItem( hDlg, IDC_MAXDISTANCE ), strBuffer );
  613.  
  614.     // Set the options in the DirectSound buffer
  615.     Set3DParameters( fDopplerFactor, fRolloffFactor, fMinDistance, fMaxDistance );
  616.  
  617.     EnableWindow( GetDlgItem( hDlg, IDC_APPLY ), g_bDeferSettings );
  618. }
  619.  
  620.  
  621.  
  622.  
  623. //-----------------------------------------------------------------------------
  624. // Name: Set3DParameters()
  625. // Desc: Set the 3D buffer parameters
  626. //-----------------------------------------------------------------------------
  627. VOID Set3DParameters( FLOAT fDopplerFactor, FLOAT fRolloffFactor,
  628.                       FLOAT fMinDistance,   FLOAT fMaxDistance )
  629. {
  630.     // Every change to 3-D sound buffer and listener settings causes 
  631.     // DirectSound to remix, at the expense of CPU cycles. 
  632.     // To minimize the performance impact of changing 3-D settings, 
  633.     // use the DS3D_DEFERRED flag in the dwApply parameter of any of 
  634.     // the IDirectSound3DListener or IDirectSound3DBuffer methods that 
  635.     // change 3-D settings. Then call the IDirectSound3DListener::CommitDeferredSettings 
  636.     // method to execute all of the deferred commands at once.
  637.     DWORD dwApplyFlag = ( g_bDeferSettings ) ? DS3D_DEFERRED : DS3D_IMMEDIATE;
  638.  
  639.     g_dsListenerParams.flDopplerFactor = fDopplerFactor;
  640.     g_dsListenerParams.flRolloffFactor = fRolloffFactor;
  641.  
  642.     if( g_pDSListener )
  643.         g_pDSListener->SetAllParameters( &g_dsListenerParams, dwApplyFlag );
  644.  
  645.     g_dsBufferParams.flMinDistance = fMinDistance;
  646.     g_dsBufferParams.flMaxDistance = fMaxDistance;
  647.  
  648.     if( g_pDS3DBuffer )
  649.         g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, dwApplyFlag );
  650. }
  651.  
  652.  
  653.  
  654.  
  655. //-----------------------------------------------------------------------------
  656. // Name: EnablePlayUI()
  657. // Desc: Enables or disables the Play UI controls 
  658. //-----------------------------------------------------------------------------
  659. VOID EnablePlayUI( HWND hDlg, BOOL bEnable )
  660. {
  661.     if( bEnable )
  662.     {
  663.         EnableWindow(   GetDlgItem( hDlg, IDC_PLAY ),       TRUE );
  664.         EnableWindow(   GetDlgItem( hDlg, IDC_STOP ),       FALSE );
  665.         SetFocus(       GetDlgItem( hDlg, IDC_PLAY ) );
  666.     }
  667.     else
  668.     {
  669.         EnableWindow(  GetDlgItem( hDlg, IDC_PLAY ),       FALSE );
  670.         EnableWindow(  GetDlgItem( hDlg, IDC_STOP ),       TRUE );
  671.         SetFocus(      GetDlgItem( hDlg, IDC_STOP ) );
  672.     }
  673. }
  674.  
  675.  
  676.  
  677.  
  678. //-----------------------------------------------------------------------------
  679. // Name: OnMovementTimer()
  680. // Desc: Periodically updates the position of the object 
  681. //-----------------------------------------------------------------------------
  682. VOID OnMovementTimer( HWND hDlg ) 
  683. {
  684.     FLOAT fXScale;
  685.     FLOAT fYScale;
  686.  
  687.     if( !g_bAllowMovementTimer )
  688.         return;
  689.  
  690.     HWND hHorzSlider = GetDlgItem( hDlg, IDC_HORIZONTAL_SLIDER );
  691.     HWND hVertSlider = GetDlgItem( hDlg, IDC_VERTICAL_SLIDER );
  692.  
  693.     fXScale = SendMessage( hHorzSlider, TBM_GETPOS, 0, 0 ) / 100.0f;
  694.     fYScale = SendMessage( hVertSlider, TBM_GETPOS, 0, 0 ) / 100.0f;
  695.     FLOAT t = timeGetTime()/1000.0f;
  696.  
  697.     // Move the sound object around the listener. The maximum radius of the
  698.     // orbit is 27.5 units.
  699.     D3DVECTOR vPosition;
  700.     vPosition.x = ORBIT_MAX_RADIUS * fXScale * (FLOAT)sin(t);
  701.     vPosition.y = 0.0f;
  702.     vPosition.z = ORBIT_MAX_RADIUS * fYScale * (FLOAT)cos(t);
  703.  
  704.     D3DVECTOR vVelocity;
  705.     vVelocity.x = ORBIT_MAX_RADIUS * fXScale * (FLOAT)sin(t+0.05f);
  706.     vVelocity.y = 0.0f;
  707.     vVelocity.z = ORBIT_MAX_RADIUS * fYScale * (FLOAT)cos(t+0.05f);
  708.  
  709.     // Show the object's position on the dialog's grid control
  710.     UpdateGrid( hDlg, vPosition.x, vPosition.z );
  711.  
  712.     // Set the sound buffer velocity and position
  713.     SetObjectProperties( &vPosition, &vVelocity );
  714. }
  715.  
  716.  
  717.  
  718.  
  719. //-----------------------------------------------------------------------------
  720. // Name: UpdateGrid()
  721. // Desc: Draws a red dot in the dialog's grid bitmap at the x,y coordinate.
  722. //-----------------------------------------------------------------------------
  723. VOID UpdateGrid( HWND hDlg, FLOAT x, FLOAT y )
  724. {
  725.     static LONG s_lX = 0;
  726.     static LONG s_lY = 0;
  727.  
  728.     // Don't update the grid if a WM_PAINT will be called soon
  729.     if( GetUpdateRect( hDlg,NULL,FALSE ) )
  730.         return;
  731.  
  732.     // Get access to the needed device contexts
  733.     HWND hWndGrid = GetDlgItem( hDlg, IDC_RENDER_WINDOW );
  734.     HDC  hDC      = GetDC( hWndGrid );
  735.     HDC  hDCbmp   = CreateCompatibleDC( hDC );
  736.     
  737.     // Select the grid bitmap into the off-screen DC
  738.     SelectObject( hDCbmp, g_hGrid );
  739.  
  740.     // Restrict painting to the grid area
  741.     IntersectClipRect( hDC, 0, 0, g_nGridW, g_nGridH );
  742.  
  743.     // Restore the area of the grid previously drawn upon
  744.     BitBlt( hDC, s_lX-1, s_lY-1, 3, 3, hDCbmp, s_lX-1, s_lY-1, SRCCOPY ); 
  745.  
  746.     // Convert the world space x,y coordinates to pixel coordinates
  747.     RECT rc;
  748.     GetClientRect( hWndGrid, &rc );
  749.     s_lX = (LONG)( ( x/ORBIT_MAX_RADIUS + 1 ) * ( rc.left + rc.right ) / 2 );
  750.     s_lY = (LONG)( (-y/ORBIT_MAX_RADIUS + 1 ) * ( rc.top + rc.bottom ) / 2 );
  751.  
  752.     // Draw a crosshair object in red pixels
  753.     SetPixel( hDC, s_lX-1, s_lY+0, 0x000000ff );
  754.     SetPixel( hDC, s_lX+0, s_lY-1, 0x000000ff );
  755.     SetPixel( hDC, s_lX+0, s_lY+0, 0x000000ff );
  756.     SetPixel( hDC, s_lX+0, s_lY+1, 0x000000ff );
  757.     SetPixel( hDC, s_lX+1, s_lY+0, 0x000000ff );
  758.  
  759.     ReleaseDC( hWndGrid, hDC );
  760.     DeleteDC( hDCbmp );
  761. }
  762.  
  763.  
  764.  
  765.  
  766. //-----------------------------------------------------------------------------
  767. // Name: SetObjectProperties()
  768. // Desc: Sets the position and velocity on the 3D buffer
  769. //-----------------------------------------------------------------------------
  770. VOID SetObjectProperties( D3DVECTOR* pvPosition, D3DVECTOR* pvVelocity )
  771. {
  772.     // Every change to 3-D sound buffer and listener settings causes 
  773.     // DirectSound to remix, at the expense of CPU cycles. 
  774.     // To minimize the performance impact of changing 3-D settings, 
  775.     // use the DS3D_DEFERRED flag in the dwApply parameter of any of 
  776.     // the IDirectSound3DListener or IDirectSound3DBuffer methods that 
  777.     // change 3-D settings. Then call the IDirectSound3DListener::CommitDeferredSettings 
  778.     // method to execute all of the deferred commands at once.
  779.     memcpy( &g_dsBufferParams.vPosition, pvPosition, sizeof(D3DVECTOR) );
  780.     memcpy( &g_dsBufferParams.vVelocity, pvVelocity, sizeof(D3DVECTOR) );
  781.  
  782.     if( g_pDS3DBuffer )
  783.         g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE );
  784. }
  785.  
  786.  
  787.  
  788.  
  789. //-----------------------------------------------------------------------------
  790. // Name: ConvertLinearSliderPosToLogScale()
  791. // Desc: Converts a linear slider position to a quasi logrithmic scale
  792. //-----------------------------------------------------------------------------
  793. FLOAT ConvertLinearSliderPosToLogScale( LONG lSliderPos )
  794. {
  795.     if( lSliderPos > 0 && lSliderPos <= 10 )
  796.     {
  797.         return lSliderPos*0.01f;
  798.     }
  799.     else if( lSliderPos > 10 && lSliderPos <= 20 )
  800.     {
  801.         return (lSliderPos-10)*0.1f;
  802.     }
  803.     else if( lSliderPos > 20 && lSliderPos <= 30 )
  804.     {
  805.         return (lSliderPos-20)*1.0f;
  806.     }
  807.     else if( lSliderPos > 30 && lSliderPos <= 40 )
  808.     {
  809.         return (lSliderPos-30)*10.0f;
  810.     }
  811.  
  812.     return 0.0f;
  813. }
  814.  
  815.  
  816.  
  817.  
  818. //-----------------------------------------------------------------------------
  819. // Name: ConvertLinearSliderPosToLogScale()
  820. // Desc: Converts a quasi logrithmic scale to a slider position
  821. //-----------------------------------------------------------------------------
  822. LONG ConvertLogScaleToLinearSliderPosTo( FLOAT fValue )
  823. {
  824.     if( fValue > 0.0f && fValue <= 0.1f )
  825.     {
  826.         return (LONG)(fValue/0.01f);
  827.     }
  828.     else if( fValue > 0.1f && fValue <= 1.0f )
  829.     {
  830.         return (LONG)(fValue/0.1f) + 10;
  831.     }
  832.     else if( fValue > 1.0f && fValue <= 10.0f )
  833.     {
  834.         return (LONG)(fValue/1.0f) + 20;
  835.     }
  836.     else if( fValue > 10.0f && fValue <= 100.0f )
  837.     {
  838.         return (LONG)(fValue/10.0f) + 30;
  839.     }
  840.  
  841.     return 0;
  842. }
  843.  
  844.  
  845.